﻿using InDepth2Demo.Model;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace InDepth2Demo.Chapter9
{
    /// <summary>
    /// 9.3 表达式树
    /// </summary>
    public class ExpressionTree
    {
        // 9.3.1 在程序中构造表达式树
        // 一个简单的表达式树，2和3 相加
        public static void SampleExpression()
        {
            Expression firstArg = Expression.Constant(2);
            Expression secondArg = Expression.Constant(3);
            Expression add = Expression.Add(firstArg, secondArg);

            Console.WriteLine(add);     //(2 + 3)
            Console.WriteLine(add.Type);
            Console.WriteLine(add.NodeType);
        }

        // 9.3.2 将表达式树编译成委托
        // 编译并执行一个表达式树
        public static void SampleExpression2()
        {
            Expression firstArg = Expression.Constant(2);
            Expression secondArg = Expression.Constant(3);
            Expression add = Expression.Add(firstArg, secondArg);
            // 创建一个在编译时委托类型已知的 Expression<TDelegate>
            Func<int> compiled = Expression.Lambda<Func<int>>(add).Compile();
            Console.WriteLine(compiled());
        }


        // Expression 类提供了一组方法和属性，用于创建和操作表达式树。
        // 表达式树是一种数据结构，用于表示代码中的表达式，并允许在运行时检查和操作这些表达式。
        // 常用于动态构建和执行 LINQ 查询、编译动态方法、构建解析器等。
        // 它不直接表示一个可以执行的委托（delegate）。

        // Expression<TDelegate> 类是一个泛型类
        // 表示一个可以编译为特定委托类型的表达式树。它包含了一个 Body 属性，表示表达式树的主体，以及一个 Parameters 属性，表示该表达式树中的参数。
        // 常用于 LINQ to Entities 查询，其中表达式树会被转换为 SQL 查询。
        // 也用于在运行时动态构建和编译委托。


        // Expression 类 示例
        public static void SimpleExpression90()
        {
            var constantExpression = Expression.Constant(42);
            var addExpression = Expression.Add(constantExpression, Expression.Constant(2));
            var lambdaExpression = Expression.Lambda<Func<int>>(addExpression);
            var compiledLambda = lambdaExpression.Compile();
            var result = compiledLambda(); // 结果为 44
        }

        // Expression<TDelegate> 类示例
        public static void SimpleExpression91()
        {
            Expression<Func<int, int, int>> addExpression = (x, y) => x + y;
            var compiledLambda = addExpression.Compile();   //编译表达式树 由描述为可执行代码的lambda 表达式，并生成一个委托，表示lambda 表达式
            var result = compiledLambda(42, 2);

            // 在 LINQ to Entities 中使用
            var query = Product.GetSampleProducts().Where(p => p.Price > 10).ToList();
        }


        //9.3.3 将 C# Lambda 表达式转换成表达式树
        public static void SimpleExpression3()
        {
            Expression<Func<int>> return5 = () => 5;
            Func<int> compiled = return5.Compile();
            Console.WriteLine(compiled());

            // 第一行中，()=>5 是 Lambda表达式。  这里的一个要点在于，Lambda 表达式已经转换成了一个表达式树。
            // 只有对单个表达式进行求值的 Lambda才可以。
        }

        // 演示一个更复杂的表达式树
        public static void SimpleExpression4()
        {
            Expression<Func<string, string, bool>> expression = (x, y) => x.StartsWith(y);
            var compiled = expression.Compile();

            Console.WriteLine(compiled("First", "Second"));
            Console.WriteLine(compiled("First", "Fir"));
        }

        // 表达式树本身则要复杂得多，尤其是等到我们把它转换成 LambdaExpression 的一个实例的时候。下面的代码展示了如何用代码来构造它。
        // 用代码来构造一个方法调用表达式树
        public static void SimpleExpression5()
        {
            // 构造方法调用的各个部件  
            MethodInfo method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            var target = Expression.Parameter(typeof(string), "x");
            var methodArg = Expression.Parameter(typeof(string), "y");
            Expression[] methodArgs = new[] { methodArg };

            // 从以上部件创建调用表达式
            Expression call = Expression.Call(target, method, methodArgs);

            // 将 call 转换成 Lambda表达式
            var lambdaParameters = new[] { target, methodArg };
            var lambda = Expression.Lambda<Func<string, string, bool>>(call, lambdaParameters);

            var compiled = lambda.Compile();

            Console.WriteLine(compiled("First", "Second"));
            Console.WriteLine(compiled("First", "Fir"));
        }


        //《Learning hard C#学习笔记》例子
        // 构造“a+b”的表达式树结构
        public static void Call()
        {
            // 表达式的参数
            ParameterExpression a = Expression.Parameter(typeof(int), "a");
            ParameterExpression b = Expression.Parameter(typeof(int), "b");

            // 表达式树的主体部分
            BinaryExpression be = Expression.Add(a, b);

            // 构造表达式树
            Expression<Func<int, int, int>> expressionTree = Expression.Lambda<Func<int, int, int>>(be, a, b);


            // 分析树结构，获取表达式树的主体部分
            BinaryExpression body = (BinaryExpression)expressionTree.Body;

            // 左节点，每个节点本身就是一个表达式对象
            ParameterExpression left = (ParameterExpression)body.Left;

            // 右节点
            ParameterExpression right = (ParameterExpression)body.Right;

            // 输出表达式树结构
            Console.WriteLine("表达式树结构为：" + expressionTree);
            // 输出
            Console.WriteLine("表达式树主体为：");
            Console.WriteLine(expressionTree.Body);
            Console.WriteLine("表达式树左节点为：{0}{4} 节点类型为：{1}{4}{4} 表达式树右节点为：{2}{4} 节点类型为：{3}{4}", left.Name, left.Type, right.Name, right.Type, Environment.NewLine);

            //输出：
            // 表达式树结构为：(a, b) => (a + b)
            // 表达式树主体为：
            // (a + b)
            // 表达式树左节点为：a
            // 节点类型为：System.Int32

            // 表达式树右节点为：b
            // 节点类型为：System.Int32
        }
    }
}
